package com.leesche.zcsp.node.net.controller;

import com.alibaba.iot.demo.util.CipherUtils;
import com.alibaba.iot.demo.util.Config;
import com.leesche.zcsp.node.net.service.NetService;
import com.leesche.zcsp.node.utils.web.messge.WebResult;
import com.leesche.zcsp.node.web.constants.Constants;
import com.leesche.zcsp.node.web.model.AppPushMessage;
import com.leesche.zcsp.node.web.model.PubDevice;
import com.leesche.zcsp.node.web.model.ServOrder;
import com.leesche.zcsp.node.web.service.PubDeviceService;
import com.leesche.zcsp.node.web.service.ServOrderService;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Map;

/**
 * @author reid
 * @Created 16/10/27
 */

@Controller
@RequestMapping("/net")
@SuppressWarnings("All")
public class NetController {

    private static final Logger LOGGER = Logger.getLogger(NetController.class);

    @Autowired
    private NetService netService;
    @Autowired
    private PubDeviceService deviceService;
    @Autowired
    private ServOrderService orderService;

    /**
     * @param request
     * @param response
     * @throws IOException
     * @Description: 设备注册
     */
    @RequestMapping(value = "/registry", method = {RequestMethod.GET, RequestMethod.POST})
    public void deviceRegistry(HttpServletRequest request, HttpServletResponse response) {
        String deviceName = request.getParameter("deviceName");
        String deviceType = request.getParameter("deviceType");
        LOGGER.info("deviceName = " + deviceName);
        LOGGER.info("deviceType = " + deviceType);
        String result = netService.regDevice(deviceName, deviceType, false);
        LOGGER.info("device result = " + result);
        try {
            response.getOutputStream().write(result.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 设备注册新接口,返回带阿里iot服务器地址
     * @param request
     * @param response
     */
    @RequestMapping(value = "/registryNew", method = {RequestMethod.GET, RequestMethod.POST})
    public void deviceRegistryNew(HttpServletRequest request, HttpServletResponse response) {
        String deviceName = request.getParameter("deviceName");
        String deviceType = request.getParameter("deviceType");
        LOGGER.info("deviceName = " + deviceName);
        LOGGER.info("deviceType = " + deviceType);
        String result = netService.regDevice(deviceName, deviceType, true);
        LOGGER.info("device result = " + result);
//        response.getWriter().write(deviceSecret);
        try {
            response.getOutputStream().write(result.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @RequestMapping(value = "/registry2", method = {RequestMethod.GET, RequestMethod.POST})
    public void deviceRegistry2(HttpServletRequest request, HttpServletResponse response) {
        String deviceName = request.getParameter("deviceName");
        String deviceType = request.getParameter("deviceType");
        String deviceSecret = netService.regDevice(deviceName, deviceType, true);

        byte[] bytes = null;
        try {
            bytes = CipherUtils.encodeDataWithAES(deviceSecret.getBytes(), Config.AES_KEY);
            LOGGER.info("加密后数据为:bytes=" + bytes);
            LOGGER.info("加密后数据为:Arrays.toString(bytes)=" + Arrays.toString(bytes));
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }

        String fileName = "device.txt";
        response.reset();// 不加这一句的话会出现下载错误
        response.setHeader("Content-disposition", "attachment; filename=" + fileName);// 设定输出文件头
        response.setContentType("text/x-plain");// 定义输出类型

        try {
            OutputStream outputStream = response.getOutputStream();
            outputStream.write(bytes);
            outputStream.flush();
            outputStream.close();
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }
    }

    /**
     * 查询设备是否在线
     * @param deviceId
     * @return
     */
    @ResponseBody
    @RequestMapping("/isOnline")
    public String isOnline(String deviceId) {
        boolean flag = netService.isOnline(deviceService.selectByPrimaryKey(Long.valueOf(deviceId)).getImme());
        return flag ? Constants.SUCCESS : Constants.FAIL;
    }

    @ResponseBody
    @RequestMapping("/auth")
    public String authDevice(String deviceName, String deviceSecret) {
        String result = netService.authDevice(deviceName, deviceSecret);
        return result;
    }

    @RequestMapping("/push")
    public void push(Long pushType, HttpServletResponse response) {
        String body = "{\"messageType\":\"1\",\"body\":\"test json body\"}";

        AppPushMessage message = new AppPushMessage();
        if (pushType == 1) {
            message.setPushType("MESSAGE");
        } else {
            message.setPushType("NOTICE");
        }
        message.setDeviceType("ANDROID");
        message.setTarget("ACCOUNT");
        message.setTargetValue("maker");
        message.setTitle("测试json");
        message.setBody(body);
        message.setMessageType(1);
        message.setAndroidOpenType("NONE");
        String messageId = netService.pushMessageToAndroid(message);
        try {
            response.getOutputStream().write(messageId.getBytes("utf-8"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 设备同步时间接口
     * @param response
     */
    @RequestMapping("/syncTime")
    public void syncTime(HttpServletResponse response) {
        long now = System.currentTimeMillis();
        try {
            response.getOutputStream().write(String.valueOf(now).getBytes("utf-8"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @RequestMapping("/info")
    public void getDeviceInfo(String deviceName) {
        netService.sendClientGetDeviceInfo(deviceName, 0);
    }

    /**
     * 设备固件升级接口
     * @param type     固件类型:1-通信小板,2-业务底板,3-第三方板
     * @param sector
     * @param response
     * @throws IOException
     */
    @RequestMapping("/update/{type}/{sector}")
    public void update(@PathVariable("type") Integer type, @PathVariable("sector") Short sector, HttpServletResponse
            response) throws
                                                                                                                               IOException {
        File file = new File("/data/hardware/comm_V1_0.bin");
//        File file = new File("C:\\Users\\reid\\Desktop\\comm_V1_0.bin");
        int length = (int) file.length();

        RandomAccessFile raf = new RandomAccessFile(file, "r");

        byte[] dataTotal = new byte[length];
        raf.read(dataTotal, 0, length);
        int fileCRC16 = getCRC16(dataTotal);

//        raf.seek(0);
        raf.seek(sector * 2048);

        byte[] dataSector;
        if ((sector + 1) * 2048 > length) {
            dataSector = new byte[length - sector * 2048];
            raf.read(dataSector, 0, length - sector * 2048);
        } else {
            dataSector = new byte[2048];
            raf.read(dataSector, 0, 2048);
        }
        int sectorCRC16 = getCRC16(dataSector);

        ByteBuffer buffer = ByteBuffer.allocate(2100);
        buffer.putInt(length);
        buffer.putShort((short) fileCRC16);
        buffer.putShort((short) 1);
        buffer.putShort(sector);
        buffer.putShort((short) sectorCRC16);
        buffer.putInt(dataSector.length);
        buffer.put(dataSector);

        buffer.flip();

        byte[] data = new byte[buffer.limit()];
        buffer.get(data);

        String fileName = "comm_V1_0.bin_" + sector;
        response.reset();// 不加这一句的话会出现下载错误
        response.setHeader("Content-disposition", "attachment; filename=" + fileName);// 设定输出文件头
        response.setContentType("text/x-plain");// 定义输出类型

        try {
            OutputStream outputStream = response.getOutputStream();
            outputStream.write(data);
            outputStream.flush();
            outputStream.close();
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }

        raf.close();
    }

    private int getCRC16(byte[] data) {
        int crc16_table[] = {0x0, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a,
                0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7,
                0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x420,
                0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac,
                0xd58d, 0x3653, 0x2672, 0x1611, 0x630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719,
                0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x840, 0x1861, 0x2802,
                0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7,
                0x6a96, 0x1a71, 0xa50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b,
                0xab1a, 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0xc60, 0x1c41, 0xedae, 0xfd8f, 0xcdec,
                0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51,
                0xe70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca,
                0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0xa1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
                0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x2b1, 0x1290, 0x22f3, 0x32d2,
                0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
                0x34e2, 0x24c3, 0x14a0, 0x481, 0x7466, 0x6447, 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8,
                0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
                0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827,
                0x18c0, 0x8e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
                0x4a75, 0x5a54, 0x6a37, 0x7a16, 0xaf1, 0x1ad0, 0x2ab3, 0x3a92, 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d,
                0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0xcc1,
                0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74,
                0x2e93, 0x3eb2, 0xed1, 0x1ef0};

        int crc16 = 0x0000;

        for (byte b : data) {
            crc16 = (crc16 << 8) ^ crc16_table[((crc16 >>> 8) ^ b) & 0xff];
//            crc16 = (crc16 >>> 8) ^ crc16_table[(crc16 ^ b) & 0xff];
        }

        return (crc16 & 0xffff);
    }

    /**
     * 在线购币&远程补币
     */
    @ResponseBody
    @RequestMapping("/buy")
    public void sendClientBuy(PubDevice device, Integer money, Integer coin, Integer payType, ServOrder order) {
        netService.sendClientBuy(device, money, coin, payType, order);
    }

    /**
     * 设置设备参数
     */
    @ResponseBody
    @RequestMapping("/setParam")
    public void setDeviceParam(String deviceName, Integer paramType, Integer paramValue) {
        netService.sendClientSetParam(deviceName, paramType, paramValue);
    }

    /**
     * 读取设备参数
     */
    @ResponseBody
    @RequestMapping(value = "/getParam",method = RequestMethod.POST)
    public Map<String,Object> sendClientGetParam(String deviceName, Integer paramType) {
        boolean flag = netService.sendClientGetParam(deviceName, paramType);
        if(flag){
            return WebResult.success().toMap();
        }else{
            return WebResult.failure("指令发送失败").toMap();
        }
    }

    /**
     * 下发升级信息
     */
    @ResponseBody
    @RequestMapping(value = "/update",method = RequestMethod.POST)
    public Map<String,Object> sendClientUpdateInfo(String deviceName, Integer type, Integer bigVersion, Integer smallVersion,
                                                   Integer option, Integer isBreak, String url) {
        boolean flag = netService.sendClientUpdateInfo(deviceName, type, bigVersion, smallVersion, option, isBreak, url);
        if(flag){
            return WebResult.success().toMap();
        }else{
            return WebResult.failure("升级失败").toMap();
        }
    }

    /**
     * 下发立即升级
     */
    @RequestMapping("/updateNow")
    public void sendClientUpdateNow(String deviceName, Integer type, Integer bigVersion, Integer smallVersion) {
        netService.sendClientUpdateNow(deviceName, type, bigVersion, smallVersion);
    }

    /**
     * 查询文件接收结果
     */
    @RequestMapping("/file")
    public void sendClientFileReceiveStatus(String deviceName, Integer type, Integer bigVersion, Integer smallVersion) {
        netService.sendClientFileReceiveStatus(deviceName, type, bigVersion, smallVersion);
    }

    /**
     * 查询固件版本
     */
    @RequestMapping("/getVersion")
    public void sendClientGetVersion(String deviceName, Integer type, HttpServletRequest request) {
        netService.sendClientGetVersion(deviceName, type);
    }

    private String getIP(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
            if (ip.equals("127.0.0.1")) {
                //根据网卡取本机配置的IP
                InetAddress inet = null;
                try {
                    inet = InetAddress.getLocalHost();
                } catch (UnknownHostException e) {
                    e.printStackTrace();
                }
                ip = inet.getHostAddress();
            }
        }
        // 对于通过多个代理的情况，第一个IP为客户端真实IP,多个IP按照','分割
        if (ip != null && ip.length() > 15) {
            if (ip.indexOf(",") > 0) {
                ip = ip.substring(0, ip.indexOf(","));
            }
        }
        return ip;
    }

}
